home *** CD-ROM | disk | FTP | other *** search
- /*
- C* -- Code generation -- Support routines.
-
- source: x2.c
- started: January 21, 1986
- version:
- February 20, 1987
- March 7, 1989
-
- PUBLIC DOMAIN SOFTWARE
-
- The CSTAR program was placed in the public domain on June 15, 1991,
- by its author and sole owner,
-
- Edward K. Ream
- 1617 Monroe Street
- Madison, WI 53711
- (608) 257-0802
-
- CSTAR may be used for any commercial or non-commercial purpose.
-
- See cstar.h or cstar.c for a DISCLAIMER OF WARRANTIES.
- */
-
- #include "cstar.h"
-
- struct node * x_addpsi(register struct node *locp,
- register struct node *loci,
- register int x_op);
- int x_shift (register unsigned long scale);
- struct node * x_scale (register struct node * loc1, unsigned long scale);
- struct node * x_subp (register struct node *loc1, struct node *loci,
- unsigned long scale);
- struct node * x_cast (register struct node *loc1,
- int len1, int imod1, int len3, bool dloc_ok);
- struct node * resolve (register struct node *loc1);
- void x_lookat(register struct node *loc1);
- struct node * x_sspush(register struct node *loc1);
- void gen_pp (struct node *p);
-
- /*
- CAUTION: the following assumptions are made in the arithmetical
- generators:
-
- 1. "A" temporaries are assumed to be valid to all 32 bits. All
- "A" word operations produce sign-extended results, so the
- only way to violate this is to EXG in a D register that has
- trash in the upper word. Generators that do this are to undo
- it before they exit.
-
- 2. A couple of routines depend explicitly on receiving integer
- loc_node arguments that are already set up to be int_type
- or long_type. Beware.
-
- 3. Pointers are everywhere implicitly and explicitly assumed to
- be long (32 bits); there is no short pointer type. Let's
- hope MacIntosh doesn't have functions that pass a short pointer
- by reference, and intend it to be 16 bits. (Since the 68000
- is bass-ackwards, in order to slavishly imitate DEC minis,
- the memory address of the 16-bit lower portion of a pointer is
- NOT the same as the memory address of the entire 32-bit
- pointer. I wonder if the 68020 has to spend extra nanoseconds
- to flip the halves of a word on a long store; I suppose either
- it does or else the memory hardware does.
-
- 4. If a loc_node contains two register entries, the first one
- is to be long. Such nodes are at present pointer nodes
- created by x_addpsi(); so the potential violation is via
- sop_cast().
- */
-
-
- /*
- Access to register parameter, for unsigned extend in casts and
- in pointer addition
- */
- extern int na_free;
- extern int nd_free;
-
- /*
- L O W L E V E L L O C _ N O D E R O U T I N E S
- */
-
- /*
- add/subtract <<< int_type or long_type only >>> to/from pointer
- loci is resolved prior to entry except when used for subtraction
-
- neither operands nor result are necessarily resolved
-
- loci is typically obtained from an arbitrary int using x_scale;
- use x_scale(loci, 1L) on unknown ints before calling this
-
- loci should NOT be used by the
- caller afterward (its temps will be freed anyhow)
-
- this code attempts to add an integer (already made signed-short
- or signed-long elsewhere) to a pointer, and prefers to do it
- by combination with the already existing node if possible. the
- sizes of constants are NOT checked here against the size limits
- imposed by the processor; that is resolve's job. the addition
- or subtraction of two GLOBALS is checked, however, since there
- is no representation for an address containing two independent
- globals, either here or in any typical linker.
-
- this code consists basically of a multitude of special cases
- */
- struct node *
- x_addpsi( register struct node *locp, register struct node *loci,
- register int x_op)
- {
- register struct node *loct, *locx;
- register struct st_node *id;
-
- register int reg;
- register long i_cnst, p_cnst;
- int gi_symbol, gp_symbol;
-
- TRACEPB("x_addpsi",
- printf("(%p, %p, %d)\n", locp, loci, x_op);
- pr_loc(locp); printf("; ");
- pr_loc(loci); printf(";\n"));
-
- /* for addition to zero, do absolutely nothing */
- if (is_zloc(loci)) {
-
- TRACEP("x_addpsi", printf("does nothing\n"));
- RETURN_PTR("x_addpsi", locp);
- }
-
- x_op = (x_op == MINUS_TOK)? X_SUB : X_ADD;
-
- /* we do intend to represent the actual sum, so we must resolve
- pointer EA loc_node. */
- if (is_ea(locp -> n_mode)) {
- locp = resolve(locp); /* we have to get it */
- if (reg = has_atreg(locp)) {
- loct = locn_reg(reg);
- free_xtemp(locp, loct);
- }
- else if (x_op == X_ADD &&
- (is_atloc(loci) ||
- (is_dtloc(loci) && loci -> n_cltype == long_type))
- ) {
- /* SHORTCUT */
- /* add the EA pointer directly to the xreg int */
- /* areg assumption: all 32 areg bits valid--true if
- EXG instruction is never used to insert them */
- g_2l1(x_op, locp, loci);
- loci -> n_cltype = locp -> n_cltype;
- RETURN_PTR("x_addpsi", loci);
- }
- else {
- loct = get_atemp();
- free_temp(locp);
- /* ss_push serves no purpose here since it has no atemp */
- }
- loct -> n_cltype = locp -> n_cltype;
- g_2l1(X_MOVEA, locp, loct);
- locp = locn_dupl(loct);
- }
- else {
- locp = locn_xdupl(locp);
- }
- /* the upshot of the above is that locp is now a VALUE */
-
- if (is_ea(loci -> n_mode) || x_op == X_SUB) {
- loci = resolve(loci);
- }
- loci = locn_xdupl(loci);
-
- /* now attempt combination of constants */
- if (loci -> n_mode == VALUE_MODE) {
- gi_symbol = gp_symbol = FALSE;
- p_cnst = locp -> n_const;
- i_cnst = loci -> n_const;
-
- /* check whether any of the symbols are global */
- if (id = locp -> n_cid) {
- if (is_rstack(id -> st_sclass) ||
- id -> st_sclass == SUE_CLASS) {
- p_cnst += id -> st_offset;
- }
- else {
- gp_symbol = TRUE;
- }
- }
-
- if (id = loci -> n_cid) {
- if (is_rstack(id -> st_sclass) ||
- id -> st_sclass == SUE_CLASS) {
- i_cnst += id -> st_offset;
- }
- else {
- gi_symbol = TRUE;
- }
- }
- if (x_op == X_SUB) {
- i_cnst = -i_cnst;
- }
- /* at this point non-global components are evaluated */
-
- /* NOTE:
- global symbols are not known until link time; they
- can't be combined here, and must be presumed to be longare generally assigned by the linker, and
- */
-
- /* transfer constants from i to p except for two globals */
- locp -> n_const += i_cnst;
- loci -> n_const = 0;
- if (gi_symbol) {
- if (gp_symbol) {
- }
- else {
- locp -> n_const = i_cnst + p_cnst;
- locp -> n_cid = loci -> n_cid;
- }
- }
- else {
- loci -> n_cid = NULL;
- }
-
- /* transfer register from i to p as space permits */
- if (x_op == X_ADD) {
- TRACEP("x_addpsi",
- printf("addition--transfer regs\n"));
- #ifdef DEBUG
- if (loci -> n_reg2) {
- g_error(NULL, "x_addpsi: internal: two i regs");
- }
- #endif /* DEBUG */
- if (loci -> n_cltype == int_type) {
- if (locp -> n_reg1 && !locp -> n_reg2) {
- locp -> n_reg2 = loci -> n_reg1;
- loci -> n_reg1 = NULL;
- locp -> n_scflag = X2_WORD;
- }
- }
- else {
- if (!locp -> n_reg1) {
- locp -> n_reg1 = loci -> n_reg1;
- loci -> n_reg1 = NULL;
- }
- else if (!locp -> n_reg2) {
- locp -> n_reg2 = loci -> n_reg1;
- locp -> n_scflag = X2_LONG;
- loci -> n_reg1 = NULL;
- }
- }
- }
- }
- TRACEP("x_addpsi",
- printf("transfers done: ");
- pr_loc(locp); printf("; ");
- pr_loc(loci); printf(";\n"));
-
- if (is_zloc(loci)) {
- /* SHORTCUT */
- RETURN_PTR("x_addpsi", locp);
- }
-
- /* get it all added up; there is a reg or const that didn't move */
- /* now try to add to a register already part of the pointer node */
- if (
- (reg = has_atreg(locp)) ||
- (is_dtreg(reg = locp -> n_reg1) && loci -> n_cltype == long_type) ||
- (is_dtreg(reg = locp -> n_reg2) &&
- ((locp->n_scflag == X2_LONG)? long_type : int_type) == loci->n_cltype)
- ) {
- TRACEP("x_addpsi", printf("locp temporary\n"));
-
- /* do it in the temporary, no cast needed */
- loct = locn_reg(reg);
- if (loci -> n_mode == VALUE_MODE) {
- loct -> n_cltype = loci -> n_cltype;
- if (loci -> n_reg1) {
- g_2l2(x_op, locn_reg(loci -> n_reg1), loct);
- }
- loci -> n_reg1 = 0;
- if (loci -> n_cid) {
- g_2l2(x_op, loci, loct);
- }
- }
- else {
- g_2l1(x_op, loci, loct);
- }
- /* all added up */
- }
- else if (x_op == X_ADD && is_atreg(reg = loci -> n_reg1)) {
- /* do it in the integer's areg */
- TRACEP("x_addpsi", printf("loci temporary\n"));
- loct = locn_reg(reg);
- loct -> n_cltype = long_type;
-
- if (is_ea(loci -> n_mode)) {
- g_2l1(X_MOVEA, loci, loct);
- free_reg(loci -> n_reg2);
- loci = loct;
- }
- else if (loci -> n_cid) {
- loci -> n_reg1 = 0;
- g_2l1(X_ADDA, loci, loct);
- }
- if (locp -> n_reg1) {
- g_2l2(X_ADDA, locn_reg(locp -> n_reg1), loct);
- }
- locp -> n_reg1 = reg;
- /* all added up */
- }
- else {
- /*
- loci and locp are both arbitrary combinations of
- registers and constants; loci may not have a
- second register, nor an n_const; it may have
- one register and/or an n_cid
-
- locp is now in VALUE mode but not necessarily
- resolved (usable as an address mode). if it
- involves a register, that register will be
- substituted with the temporary and the integer
- components added to it or subtracted from it.
- otherwise, the temporary will be inserted, and
- the integer components inserted and added or
- subtracted. for subtraction, a D temporary may
- be used.
- */
- TRACEP("x_addpsi", printf("temporary required\n"));
- if (x_op == X_SUB && !locp -> n_reg2) {
- loct = get_dtemp();
- }
- else {
- loct = get_atemp();
- }
- loct -> n_cltype = locp -> n_cltype;
-
- if (is_zloc(locp)) {
- locp = loct;
- }
- else {
- if (locp -> n_reg1) {
- /* substitute the temporary for it */
- g_2l2(X_MOVE, locn_reg(locp -> n_reg1), loct);
- free_reg(locp -> n_reg1);
- locp -> n_reg1 = loct -> n_reg1;
- }
- else {
- g_2l1(X_MOVE, locp, loct);
- locp = loct;
- }
- if (is_ea(loci -> n_mode)) {
- g_2l1(x_op, loci, loct);
- free_temp(loci);
- }
- else {
- if (loci -> n_cid) {
- /* loci -> n_const should have been
- transferred */
- locx = locn_dupl(loci);
- locx -> n_reg1 = 0;
- loci -> n_cid = 0;
- g_2l1(x_op, locx, loct);
- }
- if (loci -> n_reg1) {
- g_2l1(x_op, loci ,loct);
- }
- }
- if (is_dreg(locp -> n_reg1) && !is_dloc(locp)) {
- /* don't return a composite D-value node */
- /* note that the conditions above for drawing
- a D temp restrict the combinations
- possible here */
- locp -> n_reg1 = 0;
- g_2l1(x_op, locp, loct);
- locp = loct;
- }
- }
- /* all added up */
- if (x_op == X_SUB) {
- locp -> n_cltype = long_type;
- }
- }
- TRACEP("x_addpsi",
- printf("returns: ");
- pr_loc(locp); printf("; ");
- pr_loc(loci); printf(";\n"));
-
- RETURN_PTR("x_addpsi", locp);
- }
-
- /*
- return a shift counter if a particular scaling can be done as a shift
- */
- int
- x_shift(register unsigned long scale)
- {
- register int count;
- register unsigned long x;
-
- TRACEPB("x_shift", printf("(%lu)\n", scale));
-
- x = 1;
- count = 0;
- while (x && x < scale) {
- count++;
- x <<= 1;
- }
- if (x == scale) {
- RETURN_INT("x_shift", count);
- }
- else {
- RETURN_INT("x_shift", -1);
- }
- }
-
- /*
- Given a location containing an unscaled integer of any sort,
- return a location containing the integer multiplied by
- the scale argument, and which is always either int_type
- (signed word) or else long_type (signed vs. unsigned makes no
- difference).
-
- The returned node is ALWAYS modifiable; that is, it is never
- a node which is already attached to something in the code list.
-
- CAUTION: the postponement of scaling, if any, is someone else's
- problem.
-
- This code contains a multitude of special cases; the scaling
- process does not take quite so long as the size of this function
- suggests.
- */
- struct node *
- x_scale(register struct node * loc1, unsigned long scale)
- {
- register int imod, in_place, shift, dloc_ok;
- register struct node *loc3, *loc4;
- int cast;
-
- TRACEPB("x_scale",
- printf("(%p by %lu)\n", loc1, scale);
- pr_loc(loc1); printf(";\n"));
-
- /* ------ if it's a constant, life is very simple ------ */
- if (loc3 = fix_cloc(loc1)) {
- /* loc3 is a copy if necessary (locn_xdupl) */
- loc3 -> n_const *= (long) scale;
- if (loc3 -> n_const <= 32767 && loc3 -> n_const >= -32768L) {
- loc3 -> n_cltype = int_type;
- }
- else {
- loc3 -> n_cltype = long_type;
- }
- TRACEP("x_scale",
- printf("returns (const): ");
- pr_loc(loc3); printf(";\n"));
-
- RETURN_PTR("x_scale", loc3);
- }
-
- /* ------ decide whether a cast is necessary ------ */
- shift = x_shift(scale);
-
- imod = loc1->n_cltype->t_mclass & (LONG_MOD | CHAR_MOD | UNSIGNED_MOD);
-
- if (imod & LONG_MOD) {
- imod &= ~UNSIGNED_MOD; /* ignore sign of long */
- }
- cast = imod & (CHAR_MOD | UNSIGNED_MOD);
- /* chars and non-long unsigneds have to be exteneded */
-
- /* ------ perform special areg cast and scaling by 2 or 4 ------ */
- if (shift && na_free && !cast) { if (
- (shift == 1) ||
- (shift == 2 && (!is_dtloc(loc1) || !(imod & LONG_MOD)) )
- ) {
-
- TRACEP("x_scale", printf("special scale\n"));
-
- loc1 = resolve(loc1);
- /* SHORTCUT */
- if (!is_atloc(loc1)) {
- ss_push(loc1);
- loc3 = get_atemp();
- loc1 = ss_pop();
- g_2l1(X_MOVEA, loc1, loc3);
- free_temp(loc1);
- }
- else {
- loc3 = locn_xdupl(loc1);
- }
- loc3 -> n_cltype = long_type;
-
- while (shift--) {
- g_2l1(X_ADDA, loc3, loc3);
- }
-
- TRACEP("x_scale",
- printf("returns (areg): ");
- pr_loc(loc3); printf(";\n"));
-
- RETURN_PTR("x_scale", loc3);
- } }
-
- /* ------ cast index and scale as necessary ------ */
- if (cast || scale != 1) {
- TRACEP("x_scale", printf("cast or scale\n"));
-
- dloc_ok = (scale == 1 && EXCESSLENOK);
-
- /* perform the appropriate cast */
- if (imod & LONG_MOD) {
- loc3 = x_cast(loc1, 4, imod, 4, dloc_ok);
- }
- else if (imod & CHAR_MOD) {
- /* char to int or long in dreg */
- if (shift >= 8 ||
- ( (~imod & UNSIGNED_MOD) && scale > 32767) ||
- scale > 65535L) {
- loc3 = x_cast(loc1, 1, imod, 4, dloc_ok);
- }
- else {
- loc3 = x_cast(loc1, 1, imod, 2, dloc_ok);
- }
- }
- else if (shift > 0 || ((imod & UNSIGNED_MOD) && scale == 1) ||
- scale > 32767) {
- loc3 = x_cast(loc1, 2, imod, 4, dloc_ok);
- }
- else {
- loc3 = x_cast(loc1, 2, imod, 2, dloc_ok);
- }
-
- /* the index is now loc3, and loc1 is discarded */
-
- /* now carry out the scaling */
- if (scale != 1) {
-
- TRACEP("x_scale",
- printf("scaling required: %lx\n", scale));
-
- if (shift > 0) {
- if (shift == 1) {
- g_2l1(X_ADD, loc3, loc3);
- }
- else if (nd_free) {
- loc4 = get_dtemp();
- loc4 -> n_cltype = int_type;
- g_2l2(X_MOVE, locn_xconst((long)shift),
- loc4);
- g_2l2(X_ASL, loc4, loc3);
- free_temp(loc4);
- }
- else {
- while (shift > 8) {
- g_2l2(X_ASL, locn_xconst(8L),
- loc3);
- shift -= 8;
- }
- if (shift) {
- g_2l2(X_ASL, locn_xconst((long)shift),
- loc3);
- }
- }
- }
- /* NOTE: in CHAR_MOD with scale < 256, these
- multiplies really ought to return a sort-of
- long-or-int type */
-
- /* SIDE EFFECT: */
- else if (loc4 = locn_xconst(scale),
- (imod & UNSIGNED_MOD) && scale < 65536L) {
- g_2(X_MULU, loc4, loc3);
- loc3 -> n_cltype = long_type;
- }
- else if ((~imod & LONG_MOD) && scale <= 32767L) {
- g_2(X_MULS, loc4, loc3);
- loc3 -> n_cltype = long_type;
- }
- else {
- g_2call(loc4, loc3,
- ((imod & UNSIGNED_MOD) ||
- scale >= (unsigned long) 0x80000000L) ?
- "lmulu" : "lmul" );
- loc3 = d0_loc;
- loc3 -> n_cltype = long_type;
- }
- }
- }
- else {
- /* no cast and no scaling */
- loc3 = locn_xdupl(loc1);
- loc3 -> n_cltype = (imod & LONG_MOD)? long_type : int_type;
- }
-
- TRACEP("x_scale",
- printf("returns: ");
- pr_loc(loc3); printf(";\n"));
-
- RETURN_PTR("x_scale", loc3);
- }
-
- /*
- Subtract two pointers and descale according to given scale (do not
- take scale from either pointer)
-
- This function generates code for a LONG WORD.
- */
- struct node *
- x_subp(register struct node *loc1, struct node *loci, unsigned long scale)
- {
- register int imod, in_place, shift;
- register struct node *loc3, *loc4;
- int cast;
-
- /* this subtraction always gets done at runtime and always gets
- done in a Dreg and nothing gets moved from one node to the other */
-
- TRACEPB("x_subp", printf("(%p, %p, %lu)\n", loc1, loci, scale));
-
- loci = resolve(loci);
- loc1 = resolve(loc1);
-
- if (!is_dtloc(loc1)) {
- loc3 = get_dtemp();
- loc3 -> n_cltype = loc1 -> n_cltype;
- g_2l1(X_MOVE, loc1, loc3);
- loc1 = loc3;
- }
- loc1 = locn_xdupl(loc1);
- loc1 -> n_cltype = long_type;
-
- /* the following subtraction yields a 33-bit result */
- /* see lint.doc on folded variables */
- g_2l2(X_SUB, loci, loc1);
-
- if (scale <= 1) {
- /* SHORTCUT */
- if (scale == 1) {
- RETURN_PTR("x_subp", loc1); /* and the context better know bit 32 */
- }
- else {
- g_error(NULL, "subtraction of pointers to void");
- RETURN_PTR("x_subp", zero_loc);
- }
- }
-
- /* ------ do a shift if possible ------ */
- shift = x_shift(scale);
-
- if (shift > 0) {
- /* SHORTCUT */
- TRACEP("x_subp", printf("arithmetic shift"));
-
- g_2l2(X_ROXR, one_loc, loc1);
- shift--;
- while (shift > 8) {
- g_2l2(X_ASR, locn_xconst(8L), loc1);
- shift -= 8;
- }
- if (shift) {
- g_2l2(X_ASR, locn_xconst((long)shift), loc1);
- }
- RETURN_PTR("x_subp", loc1);
- }
- /* WARNING: this does not deal with the 33rd bit! */
- loci = locn_xconst(scale);
- loci -> n_cltype = long_type;
- g_2call(loc1, loci, "ldiv");
- d0_loc -> n_cltype = long_type;
-
- RETURN_PTR("x_subp", d0_loc);
- }
-
- /*
- Extend something and leave the result in a D temporary
- If dloc_ok, leave the result in-place even if the D
- location is not a temporary; this must be used with caution!
-
- Result type is set to int_type or long_type, for use in the
- pointer scaling routines. For sop_cast and other uses, the
- result type should be set to the cast operator type.
-
- If the extension is nil (len1 == len3), it still gets loaded.
- */
- struct node *
- x_cast(register struct node *loc1, int len1, int imod1, int len3, bool dloc_ok)
- {
- register int reg, in_place;
- register struct node *loc3;
-
- TRACEPB("x_cast", printf("(%p, %d, %d, %d, %s)\n",
- loc1, len1, imod1, len3, sl_sbout(dloc_ok)));
-
- loc1 = resolve(loc1);
-
- if (((reg = has_dtreg(loc1)) || (dloc_ok && is_dloc(loc1))) &&
- !(nd_free && len3 == 4 && (imod1 & UNSIGNED_MOD)) ) {
-
- /* dloc or dtloc and do in place */
- in_place = TRUE;
- if (is_dloc(loc1)) {
- loc3 = locn_xdupl(loc1);
- }
- else {
- loc3 = locn_reg(reg);
- g_2l1(X_MOVE, loc1, loc3);
- }
- }
- else {
- /* draw a D temp if none in node, or if unsigned-to-long */
- /* unsigned-to-16-bit is just as fast in_place */
- ss_push(loc1);
- loc3 = get_dtemp();
- loc1 = ss_pop();
- in_place = FALSE;
- }
- loc3 -> n_cltype = (len3 > 2)? long_type : int_type;
-
- /* perform actual extension in D register */
- if (len3 <= len1) {
- /* no extension */
- if (!in_place) {
- /*
- for a shrink, this moves more than needed,
- but it gets the address alignment correct
- and this is not the shrink routine anyhow;
- see sop_cast
- */
- g_2l1(X_MOVE, loc1, loc3);
- }
- }
- /* various extension operations in each case */
- /* caller is responsible for special areg casts */
- else if (imod1 & UNSIGNED_MOD) {
- if (in_place) {
- /* in place */
- if (len1 == 1) {
- g_2l2(X_AND, locn_xconst(255L), loc3);
- if (len3 > 2) {
- g_1l(X_EXT, loc3);
- }
- }
- else {
- /* len1 == 2 */
- /* andi long takes 16 clocks; this takes 12 */
- /* clearly a 68000 botch! */
- g_1(X_SWAP, loc3);
- loc3 -> n_cltype = int_type;
- g_1l(X_CLR, loc3);
- loc3 -> n_cltype = long_type;
- g_1(X_SWAP, loc3);
- }
- }
- else {
- g_1l(X_CLR, loc3);
- g_2l1(X_MOVE, loc1, loc3);
- }
- }
- else {
- /* signed extension */
- if (!in_place) {
- g_2l1(X_MOVE, loc1, loc3);
- }
- if (len1 == 1 && len3 > 2) {
- /* then: will need two extends */
- loc3 -> n_cltype = int_type;
- g_1l(X_EXT, loc3);
- loc3 -> n_cltype = long_type;
- }
- g_1l(X_EXT, loc3);
- }
- RETURN_PTR("x_cast", loc3);
- }
-
- /*
- Evaluate a node to the point where it could be used as
- an <EA> mode in a 68000 machine instruction. For EA mode
- nodes, this will typically mean adding the constant to
- one or another of the registers, or adding into a temporary,
- if the constant is out of range. For VAL mode, it means
- adding everything up, into a register if a register is
- already involved.
-
- The second register in a loc_node is never to be set up except
- by x_addpsi() and is to be X2_WORD or X2_LONG.
-
- This code is a multitude of special cases.
- */
- struct node *
- resolve(register struct node *loc1)
- {
- register struct node *locp, *locc, *loc3;
- register struct st_node *id;
- register int reg, g_symbol;
- register long i_cnst;
-
- TRACEPB("resolve",
- printf("(%p)\n", loc1);
- pr_loc(loc1); printf("\n"));
-
- g_symbol = FALSE;
- i_cnst = loc1 -> n_const;
- if (id = loc1 -> n_cid) {
- if (is_rstack(id -> st_sclass) || id->st_sclass == SUE_CLASS) {
- /* i_cnst is the true value of the const if known */
- i_cnst += id -> st_offset;
- }
- else {
- /* the true value is unknown and long */
- g_symbol = TRUE;
- }
- }
-
- if (!loc1 -> n_reg1) {
- /* constant */
-
- TRACEP("resolve",
- printf("returns (constant/constant EA): ");
- pr_loc(loc1); printf("\n"));
-
- RETURN_PTR("resolve", loc1);
- }
-
- /* from here on the node must represent a variable involving a reg */
- if (!g_symbol && i_cnst == 0 && loc1 -> n_cid) {
- loc1 = locn_xdupl(loc1);
- loc1 -> n_cid = NULL;
- loc1 -> n_const = 0;
-
- TRACEP("resolve", printf("consolidate zero\n"));
- }
-
- /* for dual-reg node: rearrange to put the "A" register first */
- /* the node was to have been set up by x_addpsi and was pointer at
- that time */
- reg = loc1 -> n_reg2;
- if ( (is_atreg(reg) && !is_atreg(loc1 -> n_reg1)) ||
- (is_areg(reg) && !is_areg(loc1 -> n_reg1)) ) {
-
- /* switch */
- loc1 = locn_xdupl(loc1);
- loc1 -> n_reg2 = loc1 -> n_reg1;
- loc1 -> n_reg1 = reg; /* the areg can be taken as long */
- loc1 -> n_scflag = X2_LONG; /* first item always long */
- }
-
- if (is_ea(loc1 -> n_mode)) {
- /* force an areg into the mode; it is otherwise unusable */
- if (!is_areg(loc1 -> n_reg1)) {
- loc3 = get_atemp();
- loc3 -> n_cltype = long_type;
- g_2l2(X_MOVEA, locn_reg(loc1 -> n_reg1), loc3);
- loc1 = locn_xdupl(loc1);
- loc1 -> n_reg1 = loc3 -> n_reg1;
- }
-
- /* now see if it is OK as is */
- if (!g_symbol &&
- ((!loc1->n_reg2 && i_cnst<=32767 && i_cnst >= -32768L)
- ||
- (i_cnst <= 127 && i_cnst >= -128))
- ) {
- /* it is a valid mode as is */
- TRACEP("resolve",
- printf("returns ");
- pr_loc(loc1); printf("\n"));
-
- RETURN_PTR("resolve", loc1);
- }
-
- /* areg node doesn't work as is; must start adding */
- /* the constant must be too big */
- locc = locn_xdupl(loc1);
- locc -> n_reg1 = locc -> n_reg2 = 0;
- locc -> n_mode = 0;
- if (g_symbol ||
- locc -> n_const <= -32768L || locc -> n_const >= 32767) {
- locc -> n_cltype = long_type;
- }
- else {
- locc -> n_cltype = int_type;
- }
-
- /* we WILL now add, so we either shortcut or else get an
- atreg in which to add */
- if (!is_atreg(loc1 -> n_reg1)) {
- /* first reg is therefore a DESIGNATED areg */
- /* WARNING:
- after we have postponement of scaling,
- we will probably want to do an ext.l
- on the D temporary in the X2_WORD case
- instead of skipping to the get-atemp
- code. For now, however, doing that produces
- silly cascades of extends and additions into
- the D register.
- */
- if (is_dtreg(loc1 -> n_reg2) &&
- loc1 -> n_scflag == X2_LONG) {
- /* SHORTCUT */
- /* add the constant to the already long dreg */
- locc -> n_cltype = long_type;
- g_2l1(X_ADD, locc, locn_reg(loc1 -> n_reg2));
- loc1 = locn_xdupl(loc1);
- loc1 -> n_cid = NULL;
- loc1 -> n_const = 0L;
-
- TRACEP("resolve",
- printf("returns (dreg): ");
- pr_loc(loc1);printf("\n"));
-
- RETURN_PTR("resolve", loc1);
- }
- loc3 = get_atemp();
- loc3 -> n_cltype = long_type;
- g_2l2(X_MOVEA, locn_reg(loc1 -> n_reg1), loc3);
- loc1 = locn_xdupl(loc1);
- loc1 -> n_reg1 = loc3 -> n_reg1;
- }
-
- /* now we have an atreg node, so all we need do is add const */
- /* 3/6/89 !loc1 was !locp */
- if (!loc1 -> n_reg2 || g_symbol ||
- i_cnst < -32768L || i_cnst > 32767) {
- /* one or two registers including an atemp */
- /* add the constant to the atemp */
- g_2l1(X_ADDA, locc, locn_reg(loc1 -> n_reg1));
- loc1 = locn_xdupl(loc1);
- loc1 -> n_cid = NULL;
- loc1 -> n_const = 0L;
- }
- else {
- /* two registers with atemp, and word constant */
- /* add the other register to the atemp */
- /* this is a judgment call; the register-to-register
- add in a sense wastes two clock cycles in some
- cases. we could add the constant to the atemp;
- in many cases that would produce an 0(a,x) mode
- that would have nothing more added to the constant,
- or tend to trigger more of the same since it's
- almost full-up; that may also in effect waste
- a couple of cycles
- */
- loc3 = locn_reg(loc1 -> n_reg2);
- loc3 -> n_cltype = (loc1 -> n_scflag == X2_WORD)?
- int_type : long_type;
- g_2l1(X_ADDA, loc3, locn_reg(loc1 -> n_reg1));
- loc1 = locn_xdupl(loc1);
- loc1 -> n_reg2 = 0;
- free_xtemp(loc3, loc1);
- }
- TRACEP("resolve",
- printf("returns: ");
- pr_loc(loc1); printf("\n"));
-
- RETURN_PTR("resolve", loc1);
- }
- else {
- /* the node is required as a value, so it has to be
- added up to yield an actual number in a single register */
- if (i_cnst == 0 && !g_symbol && !loc1 -> n_reg2) {
-
- TRACEP("resolve",
- printf("returns (as is): ");
- pr_loc(loc1); printf("\n"));
-
- RETURN_PTR("resolve", loc1);
- }
- #ifdef DEBUG
- /* the shortening cast is to resolve its target, so this
- is not to happen */
- if (mlen(loc1) < 4) {
- g_error(loc1, "resolve: internal: must not happen");
-
- TRACEP("resolve",
- printf("short combined node: ");
- pr_loc(loc1); printf("\n");
- pr_type(loc1 -> n_cltype); printf("\n"));
- }
- #endif /* DEBUG */
-
- /* find a destination */
- if (reg = has_atreg(loc1)) {
- loc3 = locn_reg(reg);
- }
- else if (is_dtreg(reg = loc1 -> n_reg1)) {
- loc3 = locn_reg(reg);
- }
- else if (loc1 -> n_scflag == X2_LONG &&
- is_dtreg(reg = loc1 -> n_reg2)) {
- loc3 = locn_reg(reg);
- }
- else {
- loc3 = get_atemp();
- /* try to pick it up with LEA in one fell swoop */
- if (!g_symbol && is_areg(loc1 -> n_reg1) &&
- (
- (!loc1->n_reg2 && i_cnst<=32767 && i_cnst >= -32768L) ||
- (i_cnst <= 127 && i_cnst >= -128) )
- ) {
- /* it is a valid mode */
- g_2(X_LEA, locn_chmod(loc1, EA_MODE), loc3);
-
- TRACEP("resolve",
- printf("returns (LEA): ");
- pr_loc(loc3);printf("\n"));
-
- free_temp(loc1);
- loc3 -> n_cltype = loc1 -> n_cltype;
- RETURN_PTR("resolve", loc3);
- }
- /* otherwise move and add */
- /* LEA of the two registers into the temp is not
- any faster, so we won't try it */
- loc3 -> n_cltype = loc1 -> n_cltype;
- g_2l2(X_MOVEA, locn_reg(loc1 -> n_reg1), loc3);
- loc3 -> n_cltype = long_type;
- free_reg(loc1 -> n_reg1);
- loc1 = locn_xdupl(loc1);
- loc1 -> n_reg1 = reg = loc3 -> n_reg1;
- }
-
- /* see if it can be obtained with LEA as is */
- /* NOTE: double-check timing & make sure this never harms */
- if (!g_symbol && is_areg(reg) &&
- (
- (!loc1->n_reg2 && i_cnst<=32767 && i_cnst >= -32768L) ||
- (i_cnst <= 127 && i_cnst >= -128) )
- ) {
- /* it is a valid mode */
- g_2(X_LEA, locn_chmod(loc1, EA_MODE), loc3);
- free_xtemp(loc1, loc3);
-
- TRACEP("resolve",
- printf("returns (LEA): ");
- pr_loc(loc3);printf("\n"));
-
- loc3 -> n_cltype = loc1 -> n_cltype;
- RETURN_PTR("resolve", loc3);
- }
-
- /* must add the other register and the constant into loc3 */
- locc = locn_xdupl(loc1);
- locc -> n_reg1 = locc -> n_reg2 = 0;
- if (g_symbol || is_dreg(reg) ||
- locc -> n_const <= -32768L || locc -> n_const >= 32767) {
- locc -> n_cltype = long_type;
- }
- else {
- locc -> n_cltype = int_type;
- }
-
- /* add the "other" register to the result */
- if (reg == loc1 -> n_reg2) {
- loc3 -> n_cltype = long_type;
- g_2l2(X_ADD, locn_reg(loc1 -> n_reg1), loc3);
- }
- else {
- if (loc1 -> n_reg2) {
- loc3->n_cltype = (loc1 -> n_scflag == X2_WORD)?
- int_type : long_type;
- g_2l2(X_ADD, locn_reg(loc1 -> n_reg2), loc3);
- }
- }
-
- /* now we have an atreg node, so all we need do is add const */
- if (g_symbol || i_cnst) {
- g_2l1(X_ADD, locc, loc3);
- }
-
- TRACEP("resolve",
- printf("returns (add): ");
- pr_loc(loc3); printf("\n"));
-
- loc3 -> n_cltype = loc1 -> n_cltype;
- free_xtemp(loc1, loc3);
- RETURN_PTR("resolve", loc3);
- }
- }
-
- /*
- Touch a loc_node in order to make sure the side effects get
- done. Typically what this does is increment the areg involved
- in a dangling EA_PRD or EA_PSI node, as when the programmer
- writes
- *x++;
- as a complete statement. This is called by the expression entry
- point routines on the item which always dangles on the stack when they
- are about to return.
- */
- void
- x_lookat(register struct node *loc1)
- {
- register struct node *loc3;
- long x;
-
- TRACEPB("x_lookat", printf("(%p)\n", loc1));
-
- switch (loc1 -> n_mode) {
- case EAPRD_MODE:
- x = (long) mlen(loc1);
- if (x == 1 && loc1 -> n_reg1 == R_A7) {
- x = 2;
- }
- loc3 = locn_reg(loc1 -> n_reg1);
- loc3 -> n_cltype = int_type;
- g_2l2(X_SUBQ, locn_xconst(x), loc3);
- break;
-
- case EAPSI_MODE:
- x = (long) mlen(loc1);
- if (x == 1 && loc1 -> n_reg1 == R_A7) {
- x = 2;
- }
- loc3 = locn_reg(loc1 -> n_reg1);
- loc3 -> n_cltype = int_type;
- g_2l2(X_ADDQ, locn_xconst(x), loc3);
- break;
- }
-
- TICKX("x_lookat");
- }
-
- /*
- Conditionally push a node onto the physical stack and return
- an adjusted node which will work later when popped from the
- SIMULATION stack. Unlike resolve(), this is not to draw a temporary.
-
- Any node containing no temporary returns NULL.
-
- Any node containing a temporary gets resolved and pushed,
- possibly by PEA. The temporary is then freed, and the caller
- may inspect nd_free/na_free to see what it is.
-
- The second register is never to be set up except
- by x_addpsi() and is signed: X2_WORD or X2_LONG.
- */
- struct node *
- x_sspush(register struct node *loc1)
- {
- register struct node *locx, *locp, *locc, *loc3;
- register struct st_node *id;
- register int reg, g_symbol;
- register long i_cnst;
- struct type_node *type1;
-
- TRACEPB("x_sspush",
- printf("(%p)\n", loc1);
- pr_loc(loc1); printf("\n"));
-
- if (!has_atreg(loc1) && !has_dtreg(loc1)) {
- TRACEP("x_sspush", printf("no temp to free\n"));
- RETURN_PTR("x_sspush", NULL);
- }
-
- /* node contains at least one temporary */
- loc1 = locn_dupl(loc1);
- /* this routine might be called again on loc1, so
- it should not alter loc1 ever */
-
- locx = NULL; /* for exit adjustment !!! */
- locp = NULL; /* for addition */
-
- /* check symbols */
- g_symbol = FALSE;
- i_cnst = loc1 -> n_const;
- if (id = loc1 -> n_cid) {
- if (is_rstack(id -> st_sclass) || id->st_sclass == SUE_CLASS) {
- /* i_cnst is the true value of the const if known */
- i_cnst += id -> st_offset;
- }
- else {
- /* the true value is unknown and long */
- g_symbol = TRUE;
- }
- }
- if (!g_symbol && i_cnst == 0 && loc1 -> n_cid) {
- loc1 -> n_cid = NULL;
- loc1 -> n_const = 0;
- TRACEP("x_sspush", printf("consolidate zero\n"));
- }
-
- /* pure register push */
- if (loc1 -> n_mode == VALUE_MODE && !loc1 -> n_cid &&
- !loc1 -> n_const && !loc1 -> n_reg2) {
- g_2l1(X_MOVE, loc1, push_loc);
- goto push_adj;
- }
-
- /* at this point, it is shown to be a combined or EA node and
- reg1 must be long */
- #ifdef DEBUG
- if (loc1 -> n_mode == VALUE_MODE && mlen(loc1) < 4) {
- g_error(loc1, "x_sspush: internal: must not happen");
-
- TRACEP("x_sspush",
- printf("short combined node: ");
- pr_loc(loc1); printf("\n");
- pr_type(loc1 -> n_cltype); printf("\n"));
- }
- #endif /* DEBUG */
-
- /* if dual-reg node, put the temporary first; put the areg first
- if two temporaries */
- if ( !(is_atreg(loc1 -> n_reg1) || is_dtreg(loc1 -> n_reg1)) ||
- (is_atreg(loc1 -> n_reg2) && !is_atreg(loc1 -> n_reg1))
- ) {
- /* switch */
- reg = loc1 -> n_reg2;
- loc1 -> n_reg2 = loc1 -> n_reg1;
- loc1 -> n_reg1 = reg; /* the areg can be taken as long */
- if (loc1 -> n_scflag != X2_LONG) {
- loc1 -> n_scflag = X2_LONG;
- if (is_dreg(reg)) {
- locp = locn_reg(reg);
- locp -> n_cltype = long_type;
- g_1l2(X_EXT, locp); /* 3/5/89: was g_2l1() */
- }
- }
- }
- /* a temporary is always first, and is always long */
-
- /* if it is EA, we MUST have an areg */
- /* if second register is short, we must have areg since we may
- not be able to cast the second register */
- if (is_dreg(loc1 -> n_reg1) &&
- (loc1 -> n_scflag != X2_LONG || is_ea(loc1 -> n_mode)) ) {
- locx = locn_reg(reg);
- a0_loc -> n_cltype = long_type;
- g_2(X_EXG, locx, a0_loc);
- loc1 -> n_reg1 = R_A0;
- }
-
- /* try to pick it up with EA/PEA in one fell swoop */
- if (!g_symbol && is_areg(loc1 -> n_reg1) &&
- ( (!loc1->n_reg2 && i_cnst<=32767 && i_cnst >= -32768L) ||
- (i_cnst <= 127 && i_cnst >= -128) )
- ) {
- if (is_ea(loc1 -> n_mode)) {
- g_2l1(X_MOVE, loc1, push_loc);
- }
- else {
- loc1 -> n_mode = EA_MODE;
- g_2(X_PEA, loc1, push_loc);
- }
- goto push_adj;
- }
-
- /* otherwise add it up */
- if (locp == 0) {
- locp = locn_reg(loc1 -> n_reg1); /* destination */
- }
- if (reg = loc1 -> n_reg2) {
- locc = locn_reg(reg);
- locc -> n_cltype = (loc1 -> n_scflag == X2_WORD)?
- int_type : long_type;
- g_2l1(X_ADD, locc, locp);
- }
- if (g_symbol || i_cnst) {
- locc = locn_dupl(loc1);
- locc -> n_reg1 = locc -> n_reg2 = 0;
- if (is_areg(locp -> n_reg1) && !g_symbol &&
- i_cnst <= 32767 && i_cnst >= -32768L) {
- locc -> n_cltype = int_type;
- }
- else {
- locc -> n_cltype = long_type;
- }
- g_2l1(X_ADD, locc, locp);
- }
- locp -> n_cltype = long_type;
- g_2l1(X_MOVE, locp, push_loc);
-
- push_adj:
- if (locx) {
- g_2(X_EXG, locx, a0_loc);
- free_reg(locx -> n_reg1);
- }
- else {
- free_reg(loc1 -> n_reg1);
- }
-
- TRACEP("x_sspush",
- printf("frees %p: ", loc1);
- pr_loc(loc1); printf("\n"));
-
- free_reg(loc1 -> n_reg2);
- loc1 = locn_xdupl(loc1);
- loc1 -> n_reg2 = 0;
- loc1 -> n_reg1 = R_A7;
- loc1 -> n_mode = EAPSI_MODE;
- loc1 -> n_cid = NULL;
- loc1 -> n_const = 0;
- RETURN_PTR("x_sspush", loc1);
- }
-
- /*
-
- Make markings on the tree as follows:
-
- process array into * and + with possible reassociation
- the tree may be null
- */
- void
- gen_pp(struct node *p)
- {
- register struct node *q, *r, *r1;
- register struct type_node *qt;
- register int op, class;
-
- SL_DISABLE();
-
- if (p == NULL) {
- return;
- }
-
- op = p -> n_type;
-
- TRACEPB("gen_pp",
- printf("node = %p->%p: %d %s: ",
- p, p -> n_cltype, op, ps_tok(op));
- pr_type(p -> n_cltype); printf("\n"));
-
- switch(op = p -> n_type) {
-
- case CALL_TOK:
- TRACEP("gen_pp", printf("call\n"));
- gen_pp(p -> n_arg1);
- gen_pp(p -> n_arg2);
- break;
-
- case SEPARATOR_TOK:
- TRACEP("gen_pp", printf("separator\n"));
- gen_pp(p -> n_car);
- gen_pp(p -> n_next); /* the separator */
- break;
-
- case ID_TOK:
- /*
- place the correct address mode into the id node
- according to the storage class; the symbol table
- must of course be correct by now!
-
- if there is no ID, the item ought to be a c-language
- numeric constant, and must be of VALUE_MODE with
- no registers, and is left unaltered
- */
- TRACEP("gen_pp", printf("id: "); pr_loc(p); printf("\n"));
- if (p -> n_cid) {
- class = p -> n_cid -> st_sclass;
- if (p -> n_reg1 == 0) switch(class) {
- case SUE_CLASS:
- /* no register content */
- break;
-
- case FORMREG_CLASS:
- TRACEP("gen_pp", printf("formal register class\n"));
-
- p -> n_mode = VALUE_MODE;
- if (p -> n_cltype &&
- p -> n_cltype -> t_typtok != INT_TYPE &&
- p -> n_cltype -> t_typtok != POINTER_TYPE) {
- g_error(p, "register declared aggregate");
- }
- else {
- if (p -> n_cid) {
- p -> n_reg1 =
- p -> n_cid -> st_misc & ST_REG;
- p -> n_cid = 0;
- }
- break;
- }
- /* FALL_THROUGH */
-
- case FORMAL_CLASS:
- /*
- all FORMALS including arrays are literally
- effective addresses; a formal array is
- literally an lvalue pointer to a[0], while
- a local or global array is a virtual pointer
- having no lvalue.
- */
- p -> n_mode = EA_MODE;
- p -> n_reg1 = R_A6;
- break;
-
- case REGISTER_CLASS:
- TRACEP("gen_pp", printf("register class\n"));
- p -> n_mode = VALUE_MODE;
- if (p -> n_cltype &&
- p -> n_cltype -> t_typtok != INT_TYPE &&
- p -> n_cltype -> t_typtok != POINTER_TYPE
- ) {
- g_error(p, "register declared aggregate");
- }
- else {
- if (p -> n_cid) {
- p -> n_reg1 =
- p -> n_cid -> st_misc & ST_REG;
- p -> n_cid = 0;
- }
- break;
- }
- /* FALL_THROUGH */
-
- case AUTO_CLASS:
- p -> n_reg1 = R_A6;
- /* FALL_THROUGH */
- default:
- if (p -> n_cltype &&
- p -> n_cltype -> t_typtok == ARRAY_TYPE) {
- p -> n_mode = VALUE_MODE;
- }
- else {
- p -> n_mode = EA_MODE;
- }
- }
-
- if ( no_local && p -> n_cid &&
- (is_rstack(class) || class == SUE_CLASS)
- ) {
- TRACEP("gen_pp",printf("fix local/element\n"));
- p -> n_const += p -> n_cid -> st_offset;
- p -> n_cid = NULL;
- }
- }
- else if (p -> n_reg1) {
- TRACEP("gen_pp", printf("manifest register\n"));
- }
- TRACEP("gen_pp", printf("-> "); pr_loc(p); printf("\n"));
- break;
-
- case ARRAY_TOK:
- gen_pp(p -> n_arg1);
- gen_pp(p -> n_arg2);
-
- TRACEP("gen_pp", printf("replace ARRAY with * and +\n"));
- q = node_dupl( (byte *) p, sizeof(struct binop_node));
- q -> n_type = PLUS_TOK;
-
- /* EXISTING node gets CHANGED to * to avoid dangling ptrs */
- p -> n_type = USTAR_TOK;
- q -> n_cltype = qt = q -> n_arg1 -> n_cltype;
-
- /*
- CAUTION: there is a tacit assumption here that
- a unop_node is the same as a binop_node, except
- for the second arg!!!
-
- NOTE: K & R are silent as to which of the following
- two associations for this operation is correct.
- They differ in the case that the i + j sum overflows,
- and the differences depend on one's interpretation
- of the automatic casting rules. The DRI compiler
- does not follow a consistent interpretation.
- */
- if (array_opt) {
- /* association: p[i + j] = *(p + (i + j)) */
- TRACEP("gen_pp", printf("array strict\n"));
- p -> n_arg1 = q;
- }
- else {
- /* association: p[i + j] = *(p + i + j) */
- TRACEP("gen_pp", printf("array reassociation\n"));
- r1 = NULL;
- r = p -> n_arg2; /* the int tree */
- while (r -> n_type == PLUS_TOK ||
- (r -> n_type == MINUS_TOK &&
- r -> n_arg1 -> n_cltype -> t_typtok == INT_TYPE)) {
- r1 = r;
- r = r1 -> n_arg1;
- }
- if (r1) {
- q -> n_arg2 = r;
- r1 -> n_arg1 = q;
-
- /* propagate type */
- for (r = p -> n_arg2; r != q; r = r -> n_arg1) {
- r -> n_cltype = qt;
- }
-
- /* set argument of USTAR */
- p -> n_arg1 = p -> n_arg2;
- }
- else {
- p -> n_arg1 = q;
- }
- }
- break;
-
- case QUESTION_TOK:
- TRACEP("gen_pp", printf("ternop\n"));
- gen_pp(p -> n_arg1);
- gen_pp(p -> n_arg2);
- gen_pp(p -> n_arg3);
-
- TRACEP("gen_pp",
- printf("node = %p again: %d %s\n", p, op, ps_tok(op));
- pr_expr(p);printf("\n"));
-
- default:
- if (is_unop(op)) {
- TRACEP("gen_pp", printf("unop\n"));
- gen_pp(p -> n_arg1);
-
- TRACEP("gen_pp",
- printf("node = %p again: %d %s\n", p, op, ps_tok(op));
- pr_expr(p);printf("\n"));
- }
- else if (is_binop(op)) {
- TRACEP("gen_pp", printf("binop\n"));
- gen_pp(p -> n_arg1);
- gen_pp(p -> n_arg2);
-
- TRACEP("gen_pp",
- printf("node = %p again: %d %s\n", p, op, ps_tok(op));
- pr_expr(p); printf("\n");
- pr_type(p -> n_cltype); printf("\n"));
- }
- else {
- TRACEP("gen_pp", printf("unknown op"));
- }
- break;
-
- } /* End switch. */
-
- TICKX("gen_pp");
- }
-